package com.nxy.cpfsfe.busi.unfyag;

import com.adtec.starring.datapool.EPOper;
import com.adtec.starring.exception.BaseException;
import com.adtec.starring.global.SysDef;
import com.adtec.starring.respool.SystemParameter;
import com.adtec.starring.struct.dta.DtaInfo;
import com.adtec.starring.util.SpringUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.nxy.cpfsfe.PubBeanSerial;
import com.nxy.cpfsfe.enumtype.*;
import com.nxy.cpfsfe.mybatis.mapper.TbAMapper;
import com.nxy.cpfsfe.mybatis.mapper.TsPCmdMapper;
import com.nxy.cpfsfe.mybatis.pojo.TbA;
import com.nxy.cpfsfe.mybatis.pojo.TsPCmd;
import com.nxy.cpfsfe.service.CpfsService;
import com.nxy.cpfsfe.util.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.session.SqlSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by lcq on 2019/12/27.
 *
 * NPS.322.001.01账户验证应答处理服务
 */
public class RealCrAcctountIdfySrvBean implements CpfsService {

    private final static Logger LOGGER = LoggerFactory.getLogger(RealCrAcctountIdfySrvBean.class);

    private SqlSession sqlSession = (SqlSession) SpringUtil.getBean("mybatisSqlSession");

    /**
     * 响应回执服务入口
     */
    @Override
    public void doService() {

        Map<String,String> bizMap = null;

        try{
            String tpId = DtaInfo.getInstance().getTpId();
            String bizMsg = (String) EPOper.get(tpId, "ReqBean[0].body[0].BizMsg");

            if(bizMsg == null){
                throw new BaseException(RespCd.NCPO0110,"报文体缺少BizMsg属性");
            }
            LOGGER.info("接收到输入BizMsg报文数据：[{}]" , bizMsg);

            try{
                bizMap = XmlUtil.xml2Map(bizMsg);
            }catch(Exception e){
                throw new BaseException(RespCd.NCPO0101,e,"报文体BizMsg属性值解析失败");
            }
            String msgCd = bizMap.get("/transaction/header/msg/msgCd");
            String refMsgCd = bizMap.get("/transaction/header/msg/refMsgCd");
            if(!MsgCdOrTpEnum.MSGCD_322.getCode().equals(refMsgCd)){
                LOGGER.warn("NCS通用处理确认报文号应为:[{}]，此报文号：[{}]非法",MsgCdOrTpEnum.MSGCD_322.getCode(),msgCd);
                return;
            }
            if(StringUtils.isEmpty(refMsgCd)){
                LOGGER.warn("NCS通用处理确认报文原报文号为空");
                return;
            }
            //根据cpfsD,cpfsSeqNo,bizSysId确定原支付流水表
            String orgCpfsSeqNo = bizMap.get("/transaction/body/FIToFIPmtStsRpt/OrgnlGrpInfAndSts/OrgnlMsgId");
            if(StringUtils.isEmpty(orgCpfsSeqNo)){
                LOGGER.warn("NCS通用处理确认报文原报文标识msgId空");
                return;
            }
            String stsId = bizMap.get("/transaction/body/FIToFICstmrCdtTrf/TxInfAndSts/RmtInf/StsId");
            if("PR01".equals(stsId)){
                //已拒绝
                throw new BaseException(StringUtil.trimObject(bizMap.get("/transaction/body/FIToFICstmrCdtTrf/StsRsnInf/Rsn/Prtry")),StringUtil.trimObject(bizMap.get("/transaction/body/FIToFICstmrCdtTrf/StsRsnInf/AddtlInf")));
            }

            String orgCpfsD = bizMap.get("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf/SttlmDt");
            String sndMbrCd = bizMap.get("/transaction/header/msg/sndMbrCd");
            TsPCmdMapper  tsPCmdMapper = sqlSession.getMapper(TsPCmdMapper.class);
            TsPCmd tsPCmd = new TsPCmd();
            tsPCmd.setCpfsD(DateUtil.str2Date(orgCpfsD,"yyyy-MM-dd"));
            tsPCmd.setCpfsSeqNo(orgCpfsSeqNo);
            tsPCmd.setSndBNo(sndMbrCd);
            tsPCmd =tsPCmdMapper.query(tsPCmd);
            if(tsPCmd != null){
                //入库账务流水表
                TbA tbA =insertTbA(bizMap,tsPCmd);

                snd140(bizMap,tbA,tsPCmd);
            }else{
                LOGGER.error("找不到原交易，业务原交易流水号[%s]，清算日期[%s]，发送行[%s]",orgCpfsSeqNo,orgCpfsD,sndMbrCd);
            }

        }catch (BaseException e){
            String errMsg = String.format("[%s]报文处理失败，业务交易流水号TrxId=[%s]，[%s]",MsgCdOrTpEnum.MSGTD_102.getCode(),bizMap != null ? bizMap.get("/root/MsgHeader/TrxId") : "",e.getErrorDesc());
            LOGGER.error(errMsg,e);
            sndFailResp(bizMap,e);
        } catch (Throwable e){
            String errMsg = String.format("[%s]报文处理失败，业务交易流水号TrxId=[%s]，[%s]",MsgCdOrTpEnum.MSGTD_102.getCode(),bizMap != null ? bizMap.get("/root/MsgHeader/TrxId") : "",e.getMessage());
            BaseException be = new BaseException(RespCd.NCPS7001,e,errMsg);
            LOGGER.error(be.getErrorDesc(),be);
            sndFailResp(bizMap,be);
        }

    }

    /**
     *  入账务流水表
     */
    private TbA insertTbA(Map<String,String> bizMap,TsPCmd tsPCmd){

        try{
            TbAMapper tbAMapper = sqlSession.getMapper(TbAMapper.class);
            TbA tbAIC = new TbA();
            tbAIC.setCpfsSeqNo(tsPCmd.getCpfsSeqNo());
            tbAIC.setCpfsD(tsPCmd.getCpfsD());
            tbAIC.setpNo("1");
            tbAIC.setShardingId(tsPCmd.getShardingId());
            tbAIC.setAcqOrgId(tsPCmd.getAcqOrgId());
            tbAIC.setDrcrFlg(TAbEnum.DrcrFlag_C.getCode());
            tbAIC.setBizTyp(tsPCmd.getBizTyp());
            tbAIC.setBizCls(tsPCmd.getBizCls());
            tbAIC.setSndSysId(tsPCmd.getBizSysId());
            tbAIC.setSndOrgId(tsPCmd.getSndBNo());
            JSONObject addInfo = JSON.parseObject(tsPCmd.getAddInfo());
            tbAIC.setRcvSysId(addInfo.getString("RcvSysId"));
            tbAIC.setRcvOrgId(tsPCmd.getRcvBNo());
            tbAIC.setxDirn(TAbEnum.XDirn_In.getCode());
            tbAIC.setpCId(SysEcodeEnum.NCS.getCode());
            tbAIC.setChlXCd(MsgCdOrTpEnum.MSGCD_140.getCode());
            tbAIC.setChlSeqNo(PubBeanSerial.getInstance().getSeqNoAndIncrea(TcSequenceEnum.MSGID.getCode()));
            tbAIC.setEndToEndId(tsPCmd.getEndToEndId());
            tbAIC.setxAmt(tsPCmd.getOrdAmt());
            tbAIC.setFeAmt(tsPCmd.getFeAmt());
            tbAIC.setCurTyp(tsPCmd.getCurTyp());
            tbAIC.setPyrBNo(StringUtil.trimObject(addInfo.get("PyrBNo")));
            tbAIC.setPyrBrchNo(StringUtil.trimObject(addInfo.get("PyrBrchNo")));
            tbAIC.setPyrA(StringUtil.trimObject(addInfo.get("PyrA")));
            tbAIC.setPyrNm(StringUtil.trimObject(addInfo.get("PyrNm")));
            tbAIC.setPyeBNo(StringUtil.trimObject(addInfo.get("PyeBNo")));
            tbAIC.setPyeBrchNo(StringUtil.trimObject(addInfo.get("PyeBrchNo")));
            tbAIC.setPyeA(StringUtil.trimObject(addInfo.get("PyeA")));
            tbAIC.setPyeNm(StringUtil.trimObject(addInfo.get("PyeNm")));
            tbAIC.setBizSta(StatEnum.BIZSTA_ING.getCode());
            tbAIC.setComMsgId(PubBeanSerial.getInstance().getSeqNoAndIncrea(TcSequenceEnum.SEQ_NB.getCode()));
            tbAIC.setChkASta(StatEnum.CHKASTA_NOT_START.getCode());
            tbAIC.setReserved1(StringUtil.trimObject(bizMap.get("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf/Remark")));
            tbAIC.setCreTm(new Timestamp(System.currentTimeMillis()));

            int result = tbAMapper.insert(tbAIC);
            if(result != 1){
                String errMsg = String.format("[%s]转[%s]入账务流水表[tb_a]失败，MyCat返回影响行数[%s]",MsgCdOrTpEnum.MSGTD_102.getCode(),MsgCdOrTpEnum.MSGCD_140.getCode(),result);
                BaseException be = new BaseException(RespCd.NCPS5002,errMsg);
                throw be;
            }

            LOGGER.info("成功录入账务流水表[tb_a]，前置流水号cpfsSeqNo=[{}]，通道通讯流水号comMsgId=[{}]，通道交易流水号chlSeqNo=[{}]",
                    tbAIC.getCpfsSeqNo(),tbAIC.getComMsgId(),tbAIC.getChlSeqNo());
            return tbAIC;
        }catch (BaseException e){
            throw e;
        }catch (Exception e){
            String errMsg = String.format("[%s]转[%s]入账务流水表[tb_a]失败，[%s]",MsgCdOrTpEnum.MSGTD_102.getCode(),MsgCdOrTpEnum.MSGCD_120.getCode(),e.getMessage());
            BaseException be = new BaseException(RespCd.NCPS5002,e,errMsg);
            throw be;
        }

    }



    /**
     *  向NCS发送NPS.140报文
     */
    private void snd140(Map<String,String> bizMap,TbA tbA,TsPCmd tsPCmd) throws Exception{

        String tpId = DtaInfo.getInstance().getTpId();
        EPOper.put(tpId, "ReqBean[0].head[0].servEcd", RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
        EPOper.put(tpId, "ReqBean[0].head[0].sndAppCd", tbA.getSndSysId());
        EPOper.put(tpId, "ReqBean[0].head[0].rcvAppCd",SysEcodeEnum.NCS.getCode());
        EPOper.put(tpId, "ReqBean[0].head[0].reqServCd", MsgCdOrTpEnum.MSGCD_140.getCode());
        EPOper.put(tpId, "ReqBean[0].head[0].initrSeqno",System.currentTimeMillis() + "");
        EPOper.getCompSDO(tpId, "ReqBody").setValue("BizMsg",build140(bizMap,tbA,tsPCmd));
        String rspsCd = RpcCommUtil.getInstance().rpcFeToGW(tpId, RpcOutputInfoEnum.OutputName_Pub_Cpfsgw.getCode(),RpcOutputInfoEnum.OutPutSvr_CpfsFwdThrdPrtS.getCode());
        if(!rspsCd.equals(RespCd.NCPI0000)){
            String errMsg = String.format("向GW发送[%s]失败，[%s]",MsgCdOrTpEnum.MSGCD_120.getCode(),(String)EPOper.get(tpId, "RspBean[0].head[0].respsInfoDesc"));
            throw new BaseException(RespCd.NCPS7001,errMsg);
        }

    }

    /**
     *  构建NPS.140报文
     */
    private String build140(Map<String,String> bizMap,TbA tbA,TsPCmd tsPCmd) throws Exception{

        XMLNodeUtil xmlReqDoc = new XMLNodeUtil(XMLNodeUtil.FROM_FILE, SysDef.WORK_DIR + SystemParameter.SRC_PATH + SysDef.FILE_SP + "xml" + SysDef.FILE_SP + "NPS_140.xml");

        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/sndAppCd","MPS");
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/sndMbrCd",tbA.getSndOrgId());
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/sndDt",DateUtil.date2Str(new Date(), "yyyyMMdd"));
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/sndTm",DateUtil.date2Str(new Date(), "HHmmss"));
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/rcvAppCd",SysEcodeEnum.NPS.getCode());
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/rcvMbrCd",tbA.getRcvOrgId());
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/seqNb",tbA.getComMsgId());
        xmlReqDoc.setNodeContentTrim("/transaction/header/msg/callTyp","ASYN");
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/MsgId",tbA.getChlSeqNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/CreDtTm",DateUtil.getISODateTime(new Date()));
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/NbOfTxs","1");
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/GrpHdr/SttlmInf/SttlmMtd","CLRG");
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtId/EndToEndId",tbA.getEndToEndId());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtId/TxId",tbA.getChlSeqNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/PmtTpInf/CtgyPurp/Prtry",tbA.getBizTyp());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/IntrBkSttlmAmt",tbA.getxAmt().toPlainString());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/ChrgBr","DEBT");
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/InstgAgt/FinInstnId/ClrSysMmbId/MmbId",tbA.getPyrBNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/InstgAgt/BrnchId/Id",tbA.getPyrBrchNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/InstdAgt/FinInstnId/ClrSysMmbId/MmbId",tbA.getPyeBNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/InstdAgt/BrnchId/Id",tbA.getPyeBrchNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/Dbtr/Nm",tbA.getPyrNm());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/Dbtr/PstlAdr/AdrLine",StringUtil.trimObject(bizMap.get("/root/MsgBody/PyerInf/PyerAddr")));
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/DbtrAcct/Id/Othr/Id",tbA.getPyrA());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/DbtrAgt/FinInstnId/ClrSysMmbId/MmbId",tbA.getPyrBrchNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/DbtrAgt/FinInstnId/Nm",StringUtil.trimObject(bizMap.get("/root/MsgBody/PyerInf/PyerBrnchNm")));
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/CdtrAgt/FinInstnId/ClrSysMmbId/MmbId",tbA.getPyeBrchNo());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/CdtrAgt/FinInstnId/Nm",StringUtil.trimObject(bizMap.get("/root/MsgBody/PyeeInf/PyeeBrnchNm")));
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/Cdtr/Nm",tbA.getPyeNm());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/Cdtr/PstlAdr/AdrLine",StringUtil.trimObject(bizMap.get("/root/MsgBody/PyeeInf/PyeeAddr")));
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/CdtrAcct/Id/Othr/Id",tbA.getPyeA());
        xmlReqDoc.setNodeContentTrim("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/Purp/Prtry",tbA.getBizCls());

        String[] ustrds = xmlReqDoc.getNodesContent("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf/Ustrd");
        ustrds[0] ="/Remark/" + (StringUtils.isNotBlank(tbA.getReserved1()) ? tbA.getReserved1() : "0");
        ustrds[1] ="/TranChnlTyp/07";
        ustrds[2] ="/SttlmDt/" + DateUtil.date3Str(tbA.getCpfsD());
        ustrds[6] ="/TransFee/0.00";

        xmlReqDoc.setNodesContent("/transaction/body/FIToFICstmrCdtTrf/CdtTrfTxInf/RmtInf/Ustrd",ustrds);
        xmlReqDoc.setNodeContentTrim("/transaction/signature", "");
        String msg = xmlReqDoc.toString();
        msg = msg.replace("<transaction>", "<transaction xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:iso:std:iso:20022:tech:xsd:NPS.120.001.01\">");
        return msg;

    }

    /**
     *  发送失败响应报文
     */
    private void sndFailResp(Map<String,String> bizMap,BaseException e){

        if(bizMap == null){
            return;
        }

        try{
            String resp501Msg = buildNginxResp(bizMap,e,MsgCdOrTpEnum.MSGTD_501.getCode());
            String resp502Msg = buildNginxResp(bizMap,e,MsgCdOrTpEnum.MSGTD_502.getCode());
            HttpUtil.responseSendJson(resp501Msg,resp502Msg,bizMap);
        }catch (BaseException e1){
            String errMsg = String.format("向业务系统[%s]返回[%s]的处理失败响应[CPFS.501或CPFS.502]失败，业务交易流水号TrxId=[%s]，[%s]",bizMap.get("/root/MsgHeader/SndSysId"),MsgCdOrTpEnum.MSGTD_103.getCode(),bizMap.get("/root/MsgHeader/TrxId"),e1.getErrorDesc());
            LOGGER.error(errMsg,e1);
        }catch (Throwable e1){
            String errMsg = String.format("向业务系统[%s]返回[%s]的处理失败响应[CPFS.501或CPFS.502]失败，业务交易流水号TrxId=[%s]，[%s]",bizMap.get("/root/MsgHeader/SndSysId"),MsgCdOrTpEnum.MSGTD_103.getCode(),bizMap.get("/root/MsgHeader/TrxId"),e1.getMessage());
            LOGGER.error(errMsg,e1);
        }

    }

    /**
     * 构建响应Nginx的报文
     */
    private String buildNginxResp(Map<String,String> bizMap,BaseException e,String msgTp) throws Exception{

        Map<String,String> buildMap = new HashMap<String,String>();
        buildMap.put("RcvSysId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/SndSysId")));
        buildMap.put("SndBankId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/RcvBankId")));
        buildMap.put("RcvBankId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/SndBankId")));
        buildMap.put("CorrId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/CorrId")));
        buildMap.put("TrxId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/TrxId")));
        buildMap.put("OriTrxId",StringUtil.trimObject(bizMap.get("/root/MsgHeader/TrxId")));
        buildMap.put("TrxStsCd",StatEnum.BIZSTA_FAIL.getCode());
        buildMap.put("BizStsCd",e.getErrorCode());
        buildMap.put("BizStsDesc",e.getErrorDesc());

        if(MsgCdOrTpEnum.MSGTD_501.getCode().equals(msgTp)){
            return ResponseUtil.buildGeneral501Xml(buildMap);
        }else{
            return ResponseUtil.buildGeneral502Xml(buildMap);
        }

    }

}
